﻿/*!
 * \file	CvImageShow.h.
 *
 * \brief	该文件中定义了显示图像相关的头文件，该类组包括了显示OpencCV中Mat图像和绘制各种Shape图像的操作
 * 			CvImageShow包括了如下类:
 * 				CImageShow:
 * 				CImageShowStaticCtrl
 * 			可以支持MFC和Qt两种窗体程序需要
 */

//#pragma once
#ifndef __CVIMAGESHOW_H__
#define __CVIMAGESHOW_H__

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <memory>

#include "ImageShow/CvImageShow.h"
#include "ImageShow/Shapes.h"
#include "Utils/CSingleton.h"
#include <mutex>


#ifdef _USE_QT_
#include <QtGui/QPainter>
#endif

namespace CvImageShow
{
#ifdef _MSC_VER		// in windows and not use Qt, use GDI+ to draw the image and shapes, need initialize the GDI+
#ifndef _USE_QT_
    class GDIPlusEvent
    {
        friend class MyUtilitis::CSingleton<GDIPlusEvent>;
    private:
        ULONG_PTR gdiplusToken;
        GDIPlusEvent()
        {
            GdiplusStartupInput gdiplusStartupInput;
            GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
        }
    public:
        ~GDIPlusEvent() {
            GdiplusShutdown(gdiplusToken);
        }
    };
#endif
#endif //

    class CV_EXPORT CImageShow
    {
    public:
        CImageShow();
        ~CImageShow();

    public:
        /*!
         *	@brief set a cv::Mat image to show
         *	@param[in] imgShow, want show image
         *  @param[in] bCopy if true, will allocate a buffer and copy the imgShow's data, false use the source image object
         *  @return false the input image type or channels not support draw.
         */
        bool setShowImage(cv::Mat& imgShow, bool bCopy = true);

        void Clear();
        bool ZoomFit( bool IsFit );
        bool ZoomFit( );
        float GetScaleRatio()
        {
            return m_fScaleRatio;
        }

        /*!
         *	@brief check had set image to show
         *	@return if had set showing image return true, otherwise return false
         *
         */
        bool HadSetShowImage() { return m_bHadSetShowImage; }

        /*!
         *	@brief check set paint area size
         *	@return if had set print area size return true, otherwise return false
         */
        bool HadSetPaintAreaSize() { return m_bHadSetPaintAreaSize; }
        cv::Point2f  ConvetPos(cv::Point2f mousePos) { return  ((mousePos - m_pointOffset) / m_fScaleRatio); }

        //直接在显示的图片上画矩形，用来实现画Slit大小
        bool SetDrawRect( cv::Size RectSize, cv::Point Centor, cv::Scalar Color )
        {
            m_RectSize = RectSize;
            m_RectCentor = Centor;
            m_RectColor = Color;
            m_IsDrawRect = true;
            return m_IsDrawRect;
        }

        bool GetDrawRect( cv::Size& RectSize, cv::Point& Centor )
        {
            RectSize = m_RectSize;
            Centor = m_RectCentor;
            return m_IsDrawRect;
        }

        void EnableDrawRect( bool IsDraw )
        {
            m_IsDrawRect = IsDraw;
        }

        //在显示的图片上画十字线
        void ShowCentor(bool _show) { m_IsShowCentor = _show; }
        bool IsShowCentor(){return m_IsShowCentor;}

        void SetCentorCross(const int col, const int row)
        {
            m_CrntorCross.x = col;
            m_CrntorCross.y = row;
        }

        const cv::Point2f  GetCentorCross()
        {
            return m_CrntorCross;
        }

        //在主界面显示一些状态日志
        bool AddLogToList(std::wstring data, int MaxSize = 1)
        {
            if( m_LogLock.try_lock_for(std::chrono::microseconds(100)) )
            {
                while(m_LogList.size() >= MaxSize)
                {
                    m_LogList.pop_front();
                }

                m_LogList.push_back(data);
                m_LogLock.unlock();
                return true;
            }
            return false;
        }

        void SetLogPos(const cv::Point2d LogPos)
        {
            m_LogPos = LogPos;
        }

        const cv::Point2d GetLogPos()
        {
            return m_LogPos;
        }

        void EnableShowLog( bool IsEnable)
        {
            m_EnableLogShow = IsEnable;
        }

        /*!
         *	@brief get the last mouse position
         */
        cv::Point2f getMouseLastPos() { return m_pointMouseLastPos; }
        Shapes::CShapeArray* getShapeArrayPtr(){ return &m_hShapes; }
        Shapes::CShapeArray m_hShapes;
    private:
        //std::shared_ptr<unsigned char> m_pShowImageData;
        //std::shared_ptr<cv::Mat> m_pShowImage;
        unsigned char* m_pShowImageData;
        cv::Mat *m_pShowImage;
        cv::Mat *m_ReSizeMatRgb;  //用来保存缩放后待显示的图片，加快显示速度
        cv::Mat *m_MatRgb;  //用来保存缩放后待显示的图片，加快显示速度
        std::mutex ImageLock;

        //在主界面显示一些状态日志
        std::list<std::wstring> m_LogList;
        std::timed_mutex m_LogLock;
        cv::Point2d m_LogPos;
        bool m_EnableLogShow;


        bool m_bHadSetShowImage;
        cv::Size m_ImageSize;  //用来保存图片的尺寸
        cv::Size m_sizePaintArea; //用来保存窗口的尺寸
        bool m_bHadSetPaintAreaSize;


        //直接在显示的图片上画矩形，用来实现画Slit大小
        cv::Size m_RectSize;
        cv::Point m_RectCentor;
        cv::Scalar m_RectColor;
        bool m_IsDrawRect;


        cv::Point2f m_pointMouseLastPos;
        cv::Point2f m_pointOffset;
        float m_fScaleRatio;

        bool m_bLeftButtonDown;
        bool m_bRightButtonDown;
        bool m_bLeftButtonDbk;
        bool m_bRightButtonDbk;

        bool m_IsFit;
        bool m_IsShowCentor;
        cv::Point2f m_CrntorCross;

    protected:
        enum DragModel {
            _DRAG_WHOLE_IMAGE_ = 0,
            _DRAG_ONE_ITEM_,
        };

        DragModel m_nDragModel;

#ifndef _USE_QT_
    #if defined(_MSC_VER) && !defined(_USE_QT_)
        std::shared_ptr<GDIPlusEvent> m_pGdiEnv;
    #endif
        void fillBackgroud(CPaintDC* pPaintDC);
        void drawMatImage(Gdiplus::Graphics* gdiPainter);
        void paintAllItem(CPaintDC* pPaintDC);
#else
        void fillBackgroud(QPainter* pPainter);
        void drawMatImage(QPainter* pPainter);
        void paintAllItem(QPainter* pPainter);
#endif

        // all message
        void leftButtonDown(const cv::Point2f& mousePos);
        void leftButtonUp(const cv::Point2f& mousePos);
        void leftButtonDblClk(const cv::Point2f& mousePos);

        void rightButtonDown(const cv::Point2f& mousePos) { (mousePos); }
        void rightButtonUp(const cv::Point2f& mousePos) { (mousePos); }
        void rightButtonDblClk(const cv::Point2f& mousePos) { (mousePos); }

        void mouseWheel(int nDelta, const cv::Point2f& mousePos);
        void mouseMove(const cv::Point2f& mousePos);

        void setFocus();
        void killFocus();

        void setPaintArea(int nWidth, int nHeight);
    };	// end for class CImageShow

}	// namespace CvImageShow

#ifdef _USE_QT_
using namespace CvImageShow;
#endif

#endif
